package is.ejs.bahamut;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.PopupWindow;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;

public class DiceRollActivity extends Activity implements SensorEventListener {
	
	
	//Fastar fyrir sensor stuffið (accelerometer stuff..)
	private SensorManager sensorManager;
	private long lastUpdate;
	// Fastar fyrir setOrientiation() föllin
	// http://developer.android.com/reference/android/widget/LinearLayout.html#VERTICAL
	private static final int VERTICAL = 1;
	private PopupWindow resultsWindow;
	
	//Fjöldi lína:
	int nrOfLines = 0;
	//ID á línu:
	int idOfLine = 0;
	
	//HashMap sem geymir idOfLine - typeValue
	Map<Integer, Integer> typeMap = new HashMap<Integer, Integer>();
	
	//HashMap sem geymir idOfLine - numberValue
	Map<Integer, Integer> numberMap = new HashMap<Integer, Integer>();
	
	//Hashmap fyrir removeButton/upButton/downButton - IdOfLine, gefur aðgang að gögnum
	Map<ImageButton, Integer> upButtonMap = new HashMap<ImageButton, Integer>();
	Map<ImageButton, Integer> downButtonMap = new HashMap<ImageButton, Integer>();
	Map<ImageButton, Integer> removeButtonMap = new HashMap<ImageButton, Integer>();

	//Hashmap fyrir removeButton - diceRollLine, gerir kleift að eyða út línum
	Map<ImageButton, LinearLayout> lineMap = new HashMap<ImageButton, LinearLayout>();
	
	//Hashmap fyrir profileTitle - diceRollProfile, gerir kleift að vista/hlaða inn profile
	Map<String, DiceRollProfile> profileMap = new HashMap<String, DiceRollProfile>();
	
	//Nafn á því profile sem verið er að vista/hlaða inn
	String profileTitle;
	
	//HashMap sem geymir idOfLine - diceTypeSpinner
	Map<Integer, Spinner> spinnerMap = new HashMap<Integer, Spinner>();
	
	//HashMap sem geymir idOfLine - diceCount
	Map<Integer, TextView> textViewMap = new HashMap<Integer, TextView>();
	
	//Random fallið okkar
	SecureRandom generator = new SecureRandom();

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.dicerolllayout);
		spawnDiceRollLine(null);
		
		//Sensor stuff
		sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
		sensorManager.registerListener(this,
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_NORMAL);
		lastUpdate = System.currentTimeMillis();
	}
	
	boolean popupShows = false;
	public void onSensorChanged(SensorEvent event) {
		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
			float[] values = event.values;
			// Movement
			float x = values[0];
			float y = values[1];
			float z = values[2];

			float accelationSquareRoot = (x * x + y * y + z * z)
					/ (SensorManager.GRAVITY_EARTH * SensorManager.GRAVITY_EARTH);
			long actualTime = System.currentTimeMillis();
			if (accelationSquareRoot >= 1.5) //
			{
				if (actualTime - lastUpdate < 1000) {
					return;
				}
				if(!popupShows) {
					diceRollCalculate(null);
					popupShows = true;
				}
			}

		}

	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub

	}

	@Override
	protected void onResume() {
		super.onResume();
		// register this class as a listener for the orientation and
		// accelerometer sensors
		sensorManager.registerListener(this,
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_NORMAL);
	}

	@Override
	protected void onPause() {
		// unregister listener
		sensorManager.unregisterListener(this);
		super.onStop();
	}
	
	//Bæta við línum:
	public void spawnDiceRollLine(View view) {
		nrOfLines++; //hækka fjölda lína
		idOfLine++; //gefa línunni númer/ID
		
		//Set diceRollLineContainer sem parent
		ViewGroup parent = (ViewGroup) findViewById(R.id.diceRollLineContainer);
		
		//Bý til inflater til að sækja xml lúkkið
		LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
		
		//Sæki diceRollLine í xml-ið sem verður parent fyrir línuna
		LinearLayout diceRollLine = (LinearLayout) inflater.inflate(R.layout.dicerollline, null);
		
		//Sæki svo hvert item fyrir sig og gef þeim nýtt (unique) id.
		Spinner diceTypeSpinner = (Spinner) diceRollLine.findViewById(R.id.spinner);
		diceTypeSpinner.setId(idOfLine);
		ArrayAdapter<CharSequence> diceTypeAdapter = ArrayAdapter.createFromResource(this, R.array.diceTypeArray, android.R.layout.simple_spinner_item);
		diceTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
	    diceTypeSpinner.setAdapter(diceTypeAdapter);
	    DiceTypeListener listener = new DiceTypeListener(idOfLine, typeMap);
	    diceTypeSpinner.setOnItemSelectedListener(listener);
		
		final TextView diceCount = (TextView) diceRollLine.findViewById(R.id.diceCount);
		diceCount.setId(idOfLine);
		numberMap.put(idOfLine, 1);
		
		final ImageButton incrementDiceCount = (ImageButton) diceRollLine.findViewById(R.id.incrementDiceCount);
		incrementDiceCount.setId(idOfLine);
		upButtonMap.put(incrementDiceCount, idOfLine);
		incrementDiceCount.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				incrementNumber(view, upButtonMap.get(incrementDiceCount), diceCount);
			}
		});
		
		final ImageButton decrementDiceCount = (ImageButton) diceRollLine.findViewById(R.id.decremetDiceCount);
		decrementDiceCount.setId(idOfLine);
		downButtonMap.put(decrementDiceCount, idOfLine);
		decrementDiceCount.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
            	decrementNumber(view, downButtonMap.get(decrementDiceCount), diceCount);
			}
		});
		
		final ImageButton removeDiceRollLine = (ImageButton) diceRollLine.findViewById(R.id.removeDiceRollLine);
		removeDiceRollLine.setId(idOfLine);
		removeButtonMap.put(removeDiceRollLine, idOfLine);
		lineMap.put(removeDiceRollLine, diceRollLine);
		removeDiceRollLine.setOnClickListener(new View.OnClickListener() {
			public void onClick(View view) {
				mutilateDiceRollLine(view, removeDiceRollLine);
			}
		});
		
		//Stilla spinnerMap og textViewMap fyrir loadProfile()
		spinnerMap.put(idOfLine, diceTypeSpinner);
		textViewMap.put(idOfLine, diceCount);
		
	    
		//Bæta svo allri línunni við á skjáinn:
		parent.addView(diceRollLine);
		
	}
	
	public void mutilateDiceRollLine (View view, ImageButton targetRemoveButton) {
		//Viljum ekki henda línunni ef hún er síðasta línan
		if (nrOfLines == 1) {
			return;
		}
		
		//Línurnar fækka
		nrOfLines--;
		
		//Viðmót uppfærist
		ViewGroup parent = (ViewGroup) findViewById(R.id.diceRollLineContainer);
		LinearLayout targetDiceRollLine = lineMap.get(targetRemoveButton);
		parent.removeView(targetDiceRollLine);
		
		//Gögn uppfærast
		int currentLine = removeButtonMap.get(targetRemoveButton);
		typeMap.remove(currentLine);
		numberMap.remove(currentLine);
	}
	
	public void incrementNumber (View view, int targetID, TextView diceRollCurrentNumber) {
		int number = numberMap.get(targetID);
		if(number == 99) {
			number = 1;
		} else {
			number++;
		}
		numberMap.put(targetID, number);
		diceRollCurrentNumber.setText(Integer.toString(number));
		diceRollCurrentNumber.refreshDrawableState();
	}
	
	public void decrementNumber (View view, int targetID, TextView diceRollCurrentNumber) {
		int number = numberMap.get(targetID);
		if(number > 1) {
			number--;
		} else {
			number = 99;
		}
		numberMap.put(targetID, number);
		diceRollCurrentNumber.setText(Integer.toString(number));
	}
	
	//Reikningurinn:
	public void diceRollCalculate(View view) {	
		/** Gögn: */ 
		int currentLineNr = 0;

		List<int[]> singlesList = new ArrayList<int[]>();
		int[] sumsList = new int[idOfLine];
		int globalSum = 0;
		for(int i=1; i <= idOfLine; i++){
			if(typeMap.containsKey(i)) {
				int number = Integer.parseInt(numberMap.get(i).toString());
				int type = Integer.parseInt(typeMap.get(i).toString());
				int sum = 0;
				int[] array = new int[number];
				
		    	for(int j=0; j < number; j++){
		    		int randomInt = generator.nextInt(type);
			    	randomInt+=1;
			    	sum += randomInt;
			    	array[j] = randomInt;
				}
				
		    	singlesList.add(array);
		    	sumsList[currentLineNr] = sum;
		    	currentLineNr++;
		    	globalSum+= sum;
			}
			
		}
		
		
		
		/** Birting: */ 
		//Poppa upp niðurstöðum
		LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View resultsLayout = inflater.inflate(R.layout.resultswindow, (ViewGroup) findViewById(R.id.resultsContainer));
		resultsWindow = new PopupWindow(resultsLayout,WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,true);
		resultsWindow.showAtLocation(this.findViewById(R.id.diceRollContainer), Gravity.CENTER, 0, 0);
		
		ViewGroup parent = (ViewGroup) findViewById(R.id.diceRollLineContainer);
		
		LinearLayout resultLineContainer = new LinearLayout(this);
		resultLineContainer.setOrientation(VERTICAL);
		resultLineContainer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
	            LayoutParams.WRAP_CONTENT));
				
		//Scrollbar
		ScrollView resultScroller = new ScrollView(this);
		resultScroller.addView(resultLineContainer);
		resultScroller.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
	            LayoutParams.WRAP_CONTENT));
		//resultScroller.setPadding(left, top, right, bottom)
		
		((ViewGroup) resultsLayout).addView(resultScroller, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
		
		//Takkinn
		final Button closePopupButton = new Button(this);
		closePopupButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                closePopup(closePopupButton);
            }
        });
		closePopupButton.setText("Close");
		closePopupButton.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
		
		currentLineNr = 0;
		int[] singlesArray;
		double expectedValue = 0;
		double standardDeviation = 0;
		for(int i=0; i <= idOfLine; i++) {
			if(typeMap.containsKey(i)) {
				
				String type = typeMap.get(i).toString();
				String number = numberMap.get(i).toString();
				double individualExpectedValue = Double.parseDouble(type)+1;
				double individualNumberOfDice = Double.parseDouble(number);
				expectedValue += (individualExpectedValue/2)*individualNumberOfDice;
				
				LinearLayout resultLine = new LinearLayout(this);
				resultLine.setOrientation(VERTICAL);
				resultLine.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
						LayoutParams.WRAP_CONTENT));
				
				TextView rollTypeLabel = new TextView(this);
				rollTypeLabel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
						LayoutParams.WRAP_CONTENT));
				rollTypeLabel.setText(type + "d " + "x " + number);
				
				TextView sumLabel = new TextView(this);
				sumLabel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
						LayoutParams.WRAP_CONTENT));
				sumLabel.setText("Sum: " + sumsList[currentLineNr]);
				
				
				TextView singleLabel = new TextView(this);
				singleLabel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
						LayoutParams.WRAP_CONTENT));
				
				String singlesString = "";
				singlesArray = singlesList.get(currentLineNr);
				currentLineNr++;
				
				
				
				for (int j = 0; j < singlesArray.length; j++ ) {
					singlesString += singlesArray[j] + ", ";
					standardDeviation += Math.pow((singlesArray[j]-individualExpectedValue),2);
				}
				singleLabel.setText("Singles: " + singlesString);
				
				resultLineContainer.addView(resultLine);
				resultLine.addView(rollTypeLabel);
				resultLine.addView(sumLabel);
				resultLine.addView(singleLabel);
			}
		}
		
		LinearLayout globalResultLine = new LinearLayout(this);
		globalResultLine.setOrientation(VERTICAL);
		globalResultLine.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));
		
		TextView globalSumLabel = new TextView(this);
		globalSumLabel.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));
		String globalSumString = "Global Sum: " + globalSum;
		
		
		
		
		//HERE BE DRAGONS, DO NOT TOUCH
		TextView expectedValueView = new TextView(this);
		expectedValueView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));
		TextView standardDeviationView = new TextView(this);
		expectedValueView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
				LayoutParams.WRAP_CONTENT));
		String expectedValueString = "Expected value: " + Double.toString(expectedValue);//"FLUFLUFLU";
		if ((double)globalSum > expectedValue){
			double percentage = ((double)globalSum/expectedValue - 1)*100;
			globalSumString += ", " + (int) percentage + "% above expected value.";
		} else {
			double percentage = ((double)globalSum/expectedValue)*100;
			globalSumString += ", " + (int) percentage + "% of the expected value.";
		}
		expectedValueView.setText(expectedValueString);
		globalSumLabel.setText(globalSumString);
		resultLineContainer.addView(expectedValueView);
		resultLineContainer.addView(globalSumLabel);
		
		standardDeviation = Math.sqrt(standardDeviation/expectedValue);
		int ix = (int)(standardDeviation * 100.0);
		double std2 = ((double)ix)/100.0;
		
		String standardDeviationString = "Standard Deviation: " + Double.toString(std2);
		standardDeviationView.setText(standardDeviationString);
		resultLineContainer.addView(standardDeviationView);
		
		//takkinn
		resultLineContainer.addView(closePopupButton);
		
	}
	
	public void closePopup(View view) {
		resultsWindow.dismiss();
		popupShows = false;
	}
	
    public void statisticsSwitch(View view) {
        //Intent myIntent = new Intent(view.getContext(), StatisticsActivity.class);
        //startActivity(myIntent);
    	//resultLineContainer.addView(mix);
    }
   	
	public void saveProfile(View view) {		
		//Opna upp popup sem biður um nafn á profile
		AlertDialog.Builder saveAlert = new AlertDialog.Builder(this);
		saveAlert.setTitle(R.string.saveProfileAlertTitle);
		saveAlert.setMessage(R.string.saveProfileAlertMessage);
		
		final EditText saveEdit = new EditText(this);
		saveAlert.setView(saveEdit);
		saveAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				DiceRollProfile newProfile = new DiceRollProfile(typeMap, numberMap, nrOfLines);
				profileTitle = saveEdit.getText().toString();
				profileMap.put(profileTitle, newProfile);
			}
		});
		
		saveAlert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			  public void onClick(DialogInterface dialog, int whichButton) {
			    // Canceled.
			  }
			});

		saveAlert.show();	
	}
	
	public void loadProfile(View view) {
		//Hafa profileTitle tómt til að passa að bahamut hrynji ekki ef profileMap er tómt
		profileTitle = null;
		
		//Opna upp popup sem biður um nafn á profile
		AlertDialog.Builder loadAlert = new AlertDialog.Builder(this);
		loadAlert.setTitle(R.string.loadProfileAlertTitle);
		loadAlert.setMessage(R.string.loadProfileAlertMessage);
		
		final Spinner loadSpinner = new Spinner(this);
		loadSpinner.setPromptId(R.string.loadSpinnerPrompt);
		ArrayList<String> titleList = new ArrayList<String>();
		Set<String> profileKeySet = profileMap.keySet();
		Iterator<String> profileIterator = new ArrayList<String>(profileKeySet).iterator();
		for(int i=0; i < profileKeySet.size(); i++) {
			titleList.add(profileIterator.next());
		}
		ArrayAdapter<String> adapter = new ArrayAdapter<String>
			(this, android.R.layout.simple_spinner_item, titleList);


		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		loadSpinner.setAdapter(adapter);
	    final LoadProfileListener listener = new LoadProfileListener();
	    loadSpinner.setOnItemSelectedListener(listener);

	    loadAlert.setView(loadSpinner);
		loadAlert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
			public void onClick(DialogInterface dialog, int whichButton) {
				profileTitle = listener.getProfileTitle();
				if(profileTitle!=null)
					spawnProfile();
			}
		});
		
		loadAlert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
			  public void onClick(DialogInterface dialog, int whichButton) {
			    // Canceled.
			  }
			});	
		
	    loadAlert.show();
	}
	
	protected void spawnProfile() {
		//Sækja profile hlutinn sem á að hlaða inn
		DiceRollProfile targetProfile = profileMap.get(profileTitle);
		
		//Næ í gögnin úr því profile
		int [] typeArray = targetProfile.getTypeArray();
		int [] numberArray = targetProfile.getNumberArray();
			
		//Set diceRollLineContainer sem parent
		ViewGroup parent = (ViewGroup) findViewById(R.id.diceRollLineContainer);
		
		//Henda út öllum diceRollLines úr diceRollLineContainer
		parent.removeAllViews();

		//Upphafstilla gögn 
		typeMap.clear();
		numberMap.clear();
		upButtonMap.clear();
		downButtonMap.clear();
		removeButtonMap.clear();
		lineMap.clear();
		idOfLine = 0;
		nrOfLines = 0;
	    
	    //Fjölda lína í því profile sem skal hlaða
	    int targetNrOfLines = targetProfile.getNrOfLines();
						
		//Mun síðan "spawna" réttan fjölda lína og stilla þær eins og targetProfile lýsir (ekki þá fyrstu)
		for(int i=0; i < targetNrOfLines; i++){
			//Sækja diceType og diceNumber næstu línu í profile:
			int diceType = typeArray[i];
			int diceNumber = numberArray[i];
			
			//Búa til næstu línu
			spawnDiceRollLine(null);
			
			//Stilla gögn línunar eftir profile:
			typeMap.put(idOfLine, diceType);
			numberMap.put(idOfLine, diceNumber);
			
			//Stilla views línunnar eftir profile:
		    switch (diceType) {
			case 6:
				spinnerMap.get(idOfLine).setSelection(0);
				break;
			case 12:
				spinnerMap.get(idOfLine).setSelection(1);
				break;
			case 20:
				spinnerMap.get(idOfLine).setSelection(2);
				break;
			case 100:
				spinnerMap.get(idOfLine).setSelection(3);
				break;
			default:
				break;
			}
		    textViewMap.get(idOfLine).setText(Integer.toString(diceNumber));				   
		}	
	}
}